<?php
/** @noinspection PhpUnused */

namespace app\admin\controller\shop;

use app\admin\model\shop\goods\Goods;
use app\admin\model\shop\order\Order;
use app\admin\model\shop\order\OrderDetail;
use app\admin\model\shop\order\Refund;
use app\admin\model\shop\user\User;
use app\shop\enums\order\OrderStatus;
use app\shop\enums\order\refund\RefundAuditStatus;
use app\shop\library\datetime\DateHelper;
use app\shop\library\datetime\TimeHelper;
use app\shop\library\ShopHelper;
use think\db\exception\DbException;

class Dashboard extends Base
{
    private Order       $orderModel;
    private OrderDetail $orderDetailModel;
    private User        $userModel;
    private Goods       $goodsModel;
    private Refund      $refundModel;

    protected array $noNeedPermission = ['getStatisticsChart'];

    public function initialize(): void
    {
        parent::initialize();

        $this->orderModel       = new Order();
        $this->orderDetailModel = new OrderDetail();
        $this->userModel        = new User();
        $this->goodsModel       = new Goods();
        $this->refundModel      = new Refund();
    }

    public function index(): void
    {
        $this->success('', [
            'remark'                => get_route_remark(),
            'boardData'             => $this->boardData(),
            'orderData'             => $this->getOrderData(),
            'orderSaleData'         => $this->getOrderSaleData(),
            'userData'              => $this->getUserStatisticsData(),
            'orderStatisticsChart'  => $this->orderStatisticsChart(),
            'userStatisticsChart'   => $this->userStatisticsChart(),
            'userConsumeRatioChart' => $this->userConsumeRatioChart(),
            'goodsSaleChart'        => $this->goodsSaleStatisticsData(),
        ]);
    }

    /**
     * 订单数据
     * @return array[]
     */
    private function getOrderData(): array
    {
        $orderModel = new Order();

        $where = [];

        $totalCount = $orderModel->where($where)->count();

        $todayCount = $orderModel->where($where)->whereDay('create_time')->count();
        $weekCount  = $orderModel->where($where)->whereWeek('create_time')->count();
        $monthCount = $orderModel->where($where)->whereMonth('create_time')->count();

        $yesterdayCount = $orderModel->where($where)->whereDay('create_time', 'yesterday')->count();
        $lastWeekCount  = $orderModel->where($where)->whereWeek('create_time', 'last week')->count();
        $lastMonthCount = $orderModel->where($where)->whereMonth('create_time', 'last month')->count();

        $dayCompare   = $this->getComparePercentage($todayCount, $yesterdayCount);
        $weekCompare  = $this->getComparePercentage($weekCount, $lastWeekCount);
        $monthCompare = $this->getComparePercentage($monthCount, $lastMonthCount);

        return [
            [
                'label'        => '订单总量',
                'value'        => $totalCount,
                'compareLabel' => '',
                'compareValue' => ''
            ],
            [
                'label'        => '今日订单数',
                'value'        => $todayCount,
                'compareLabel' => '日环比',
                'compareValue' => $dayCompare
            ],
            [
                'label'        => '本周订单数',
                'value'        => $weekCount,
                'compareLabel' => '周环比',
                'compareValue' => $weekCompare
            ],
            [
                'label'        => '本月订单数',
                'value'        => $monthCount,
                'compareLabel' => '月环比',
                'compareValue' => $monthCompare
            ],
        ];
    }

    /**
     * 订单销量数据
     * @return array[]
     */
    private function getOrderSaleData(): array
    {
        $orderModel = new Order();

        $where = [
            [
                'status', 'in',
                [
                    OrderStatus::TO_SHIPPED,
                    OrderStatus::TO_RECEIVED,
                    OrderStatus::TO_EVALUATE,
                    OrderStatus::COMPLETE,
                ]
            ]
        ];

        $totalSales = $orderModel->where($where)->sum('total_price');

        $todaySales = $orderModel->where($where)->whereDay('create_time')->sum('total_price');
        $weekSales  = $orderModel->where($where)->whereWeek('create_time')->sum('total_price');
        $monthSales = $orderModel->where($where)->whereMonth('create_time')->sum('total_price');

        $yesterdaySales = $orderModel->where($where)
            ->whereDay('create_time', 'yesterday')
            ->sum('total_price');

        $lastWeekSales = $orderModel->where($where)
            ->whereWeek('create_time', 'last week')
            ->sum('total_price');

        $lastMonthSales = $orderModel->where($where)
            ->whereMonth('create_time', 'last month')
            ->sum('total_price');

        $daySalesCompare   = $this->getComparePercentage($todaySales, $yesterdaySales);
        $weekSalesCompare  = $this->getComparePercentage($weekSales, $lastWeekSales);
        $monthSalesCompare = $this->getComparePercentage($monthSales, $lastMonthSales);

        return [
            [
                'label' => '销售总额',
                'value' => shopHelper::format_price($totalSales)
            ],
            [
                'label'        => '今日销售额',
                'value'        => shopHelper::format_price($todaySales),
                'compareLabel' => '日环比',
                'compareValue' => $daySalesCompare
            ],
            [
                'label'        => '本周销售额',
                'value'        => shopHelper::format_price($weekSales),
                'compareLabel' => '周环比',
                'compareValue' => $weekSalesCompare
            ],
            [
                'label'        => '本月销售额',
                'value'        => shopHelper::format_price($monthSales),
                'compareLabel' => '月环比',
                'compareValue' => $monthSalesCompare
            ],
        ];
    }


    /**
     * 环比计算
     * @param $current
     * @param $last
     * @return string
     */
    private function getComparePercentage($current, $last): string
    {
        if ($last == 0) {
            return '--';
        }
        $percentage = (($current - $last) / $last) * 100;
        if ($percentage == 0) {
            return '--';
        }

        return shopHelper::format_price(floatval($percentage));
    }


    /**
     * 获取用户统计数据
     * @return array[]
     */
    private function getUserStatisticsData(): array
    {
        $userModel = new User();

        $where = [];

        $totalCount = $userModel->where($where)->count();

        $todayCount = $userModel->where($where)->whereDay('create_time')->count();
        $weekCount  = $userModel->where($where)->whereWeek('create_time')->count();
        $monthCount = $userModel->where($where)->whereMonth('create_time')->count();

        $yesterdayCount = $userModel->where($where)->whereDay('create_time', 'yesterday')->count();
        $lastWeekCount  = $userModel->where($where)->whereWeek('create_time', 'last week')->count();
        $lastMonthCount = $userModel->where($where)->whereMonth('create_time', 'last month')->count();

        $dayCompare   = $this->getComparePercentage($todayCount, $yesterdayCount);
        $weekCompare  = $this->getComparePercentage($weekCount, $lastWeekCount);
        $monthCompare = $this->getComparePercentage($monthCount, $lastMonthCount);

        return [
            [
                'label' => '用户总数',
                'value' => $totalCount
            ],
            [
                'label'        => '今日新增用户',
                'value'        => $todayCount,
                'compareLabel' => '日环比',
                'compareValue' => $dayCompare
            ],
            [
                'label'        => '本周新增用户',
                'value'        => $weekCount,
                'compareLabel' => '周环比',
                'compareValue' => $weekCompare
            ],
            [
                'label'        => '本月新增用户',
                'value'        => $monthCount,
                'compareLabel' => '月环比',
                'compareValue' => $monthCompare
            ],
        ];
    }

    public function getStatisticsChart(): void
    {
        $params = $this->request->param();

        $type      = $params['type'] ?? 'order';
        $timeRange = $params['range'] ?? [];

        [$startTime, $endTime] = $timeRange;
        if (!TimeHelper::isTimestamp($startTime) || !TimeHelper::isTimestamp($endTime)) {
            $this->error('时间范围有误');
        }

        $data = match ($type) {
            'user' => $this->userStatisticsChart($startTime, $endTime),
            default => $this->orderStatisticsChart($startTime, $endTime),
        };

        $this->success('', $data);
    }

    /**
     * 订单统计图
     * @param int|string $startTime
     * @param int|string $endTime
     * @return array
     */
    private function orderStatisticsChart(int|string $startTime = '', int|string $endTime = ''): array
    {
        // 默认当天
        $startTime = $startTime ?: strtotime('today midnight');
        $endTime   = $endTime ?: strtotime('today 23:59:59');

        $where = [
            [
                'status', 'in',
                [
                    OrderStatus::TO_SHIPPED,
                    OrderStatus::TO_RECEIVED,
                    OrderStatus::TO_EVALUATE,
                    OrderStatus::COMPLETE,
                ]
            ],
            [
                'create_time', 'between', [$startTime, $endTime]
            ]
        ];

        if (TimeHelper::diffDays($startTime, $endTime) == 0) {
            $field = [
                'DATE_FORMAT(FROM_UNIXTIME(create_time), "%H:00") AS time',
                'COUNT(id) AS total',
                'SUM(total_price) AS totalSale'
            ];
            // 定义分组字段
            $group = 'DATE_FORMAT(FROM_UNIXTIME(create_time), "%H:00")';

            $rangeDates = TimeHelper::getHoursBetweenTime($startTime, $endTime);
        } else {
            $field = ['date(FROM_UNIXTIME(create_time)) as time', 'count(id) as total', 'sum(total_price) as totalSale'];
            $group = 'date(FROM_UNIXTIME(create_time))';

            $rangeDates = DateHelper::getAllDateBetweenDates($startTime, $endTime);
        }

        $orderData = $this->orderModel
            ->where($where)
            ->field($field)
            ->group($group)
            ->select()
            ->toArray();

        $dates = array_map(fn($date) => [
            'time'      => $date,
            'total'     => '0',
            'totalSale' => '0.00',
        ], $rangeDates);

        return ShopHelper::merge_arrays('time', $orderData, $dates);
    }

    /**
     * 用户统计图
     * @param int|string $startTime
     * @param int|string $endTime
     * @return array
     */
    private function userStatisticsChart(int|string $startTime = '', int|string $endTime = ''): array
    {
        // 默认当天
        $startTime = $startTime ?: strtotime('today midnight');
        $endTime   = $endTime ?: strtotime('today 23:59:59');

        $where = [
            [
                'create_time', 'between', [$startTime, $endTime]
            ]
        ];

        if (TimeHelper::diffDays($startTime, $endTime) == 0) {
            $field = [
                'DATE_FORMAT(FROM_UNIXTIME(create_time), "%H:00") AS time',
                'COUNT(id) AS total',
            ];
            // 定义分组字段
            $group = 'DATE_FORMAT(FROM_UNIXTIME(create_time), "%H:00")';

            $rangeDates = TimeHelper::getHoursBetweenTime($startTime, $endTime);
        } else {
            $field = ['date(FROM_UNIXTIME(create_time)) as time', 'count(id) as total'];
            $group = 'date(FROM_UNIXTIME(create_time))';

            $rangeDates = DateHelper::getAllDateBetweenDates($startTime, $endTime);
        }

        $userData = $this->userModel
            ->where($where)
            ->field($field)
            ->group($group)
            ->select()
            ->toArray();

        $dates = array_map(fn($date) => [
            'time'  => $date,
            'total' => '0',
        ], $rangeDates);

        return ShopHelper::merge_arrays('time', $userData, $dates);
    }

    /**
     * 用户消费比例图
     * @return array
     */
    private function userConsumeRatioChart(): array
    {
        return $this->orderModel
            ->alias('order')
            ->leftJoin([$this->userModel->getTable() => 'user'], 'order.user_id = user.id')
            ->field(['user.nickname as name', 'SUM(order.pay_price) as value'])
            ->group('order.user_id')
            ->where('order.status', 'in', [
                OrderStatus::TO_SHIPPED,
                OrderStatus::TO_RECEIVED,
                OrderStatus::TO_EVALUATE,
                OrderStatus::COMPLETE,
            ])
            ->order('value', 'desc')
            ->limit(10)
            ->select()
            ->toArray();
    }

    /**
     * 商品销售统计图
     * @return array
     */
    private function goodsSaleStatisticsData(): array
    {
        return $this->orderDetailModel
            ->alias('detail')
            ->leftJoin([$this->goodsModel->getTable() => 'goods'], 'detail.goods_id = goods.id')
            ->leftJoin([$this->orderModel->getTable() => 'order'], 'detail.order_id = order.id')
            ->field([
                'goods.id',
                'goods.name as goods_name',
                'count(detail.id) as sale_volume',
                'sum(detail.total_price) as sale_values'
            ])
            ->where([
                [
                    'order.status', 'in',
                    [
                        OrderStatus::TO_SHIPPED,
                        OrderStatus::TO_RECEIVED,
                        OrderStatus::TO_EVALUATE,
                        OrderStatus::COMPLETE,
                    ]
                ]
            ])
            ->group('detail.goods_id')
            ->order(['sale_volume' => 'desc', 'sale_values' => 'desc'])
            ->limit(10)
            ->select()
            ->each(function ($item) {
                $item->sale_volume = $item->sale_volume ?: 0;
                $item->sale_values = $item->sale_values ? floatval(shopHelper::format_price($item->sale_values)) : 0;
            })
            ->toArray();
    }

    /**
     * 面板统计数据
     * @return array
     * @throws DbException
     */
    private function boardData(): array
    {
        $orderCount = $this->orderModel
            ->field(['status', 'count(id) as total'])
            ->where('status', 'in', [OrderStatus::TO_SHIPPED, OrderStatus::REFUND])
            ->group('status')
            ->select()
            ->toArray();

        $refundAuditCount = $this->refundModel->where('audit_status', RefundAuditStatus::WAIT_AUDIT)->count();

        $stockAlertCount = $this->goodsModel->where([
            ['status', '=', 1],
            ['total_stock', '<=', 10]
        ])->count();

        return [
            'to_shipped_count'   => $orderCount[0]['total'] ?? 0,
            'cancel_count'       => $orderCount[1]['total'] ?? 0,
            'refund_audit_count' => $refundAuditCount,
            'stock_alert_count'  => $stockAlertCount,
        ];
    }
}